#ifndef XG_YMAL_H
#define XG_YMAL_H
//////////////////////////////////////////////////////////////////
#include "std.h"

#define YAML_NONE 	0
#define YAML_VALUE	1
#define YAML_ARRAY	2
#define YAML_OBJECT	3

class YAMLNode : public Object
{
	friend class YAMLoader;

protected:
	string name;
	string value;
	int type = YAML_NONE;
	vector<sp<YAMLNode>> children;
	
	static int SpaceLength(const string& line);
	static string SpaceUnit(const vector<string>& content);
	static int Parse(YAMLNode* node, vector<string>& content, const string& indent, const string& step, int line);

public:
	void clear()
	{
		name.clear();
		value.clear();
		children.clear();
		type = YAML_NONE;
	}
	bool isValue() const
	{
		return type == YAML_VALUE;
	}
	bool isArray() const
	{
		return type == YAML_ARRAY;
	}
	bool isObject() const
	{
		return type == YAML_OBJECT;
	}
	const string& getName() const
	{
		return name;
	}
	const string& getValue() const
	{
		return value;
	}
	const vector<sp<YAMLNode>>& getChildren() const
	{
		return children;
	}

	bool parse(const string& content);
	bool parse(const string& content, string& step);
	
	string toString() const;
	string toString(const string& indent, const string& step) const;

	sp<YAMLNode> create(const string& path);
	sp<YAMLNode> get(const string& path) const;
	sp<YAMLNode> child(const string& name) const;
};

class YAMLoader : public Object
{
	string path;
	string step;
	YAMLNode doc;

public:
	bool reload();
	bool canUse() const;
	string toString() const;
	static YAMLoader* Instance();
	bool open(const string& path);
	const YAMLNode* document() const;
	bool parse(const string& msg, const string& name);
	bool raw(const string& path, string& value) const;
	bool get(const string& path, string& value) const;
	void set(const string& path, const string& value);
	bool list(const string& path, vector<string>& reslist) const;
	bool list(const string& path, map<string, string>& resmap) const;

	const string& getFilePath() const;
	string raw(const string& path) const;
	string get(const string& path) const;
	size_t capacity(const string& path) const;
	bool get(const string& path, int& value) const;
	bool get(const string& path, bool& value) const;
	bool get(const string& path, long& value) const;
	bool get(const string& path, double& value) const;
	map<string, string> list(const string& path) const;

	template<class DATA_TYPE> void set(const string& path, DATA_TYPE value)
	{
		set(path, stdx::str(value));
	}
};

namespace yaml
{
	static bool reload()
	{
		return YAMLoader::Instance()->reload();
	}

	static bool open(const string& path)
	{
		return YAMLoader::Instance()->open(path);
	}

	static string raw(const string& path)
	{
		return YAMLoader::Instance()->raw(path);
	}

	static string config(const string& path)
	{
		return YAMLoader::Instance()->get(path);
	}

	static size_t capacity(const string& path)
	{
		return YAMLoader::Instance()->capacity(path);
	}

	static map<string, string> list(const string& path)
	{
		return YAMLoader::Instance()->list(path);
	}

	static void set(const string& path, const string& value)
	{
		YAMLoader::Instance()->set(path, value);
	}

	static bool list(const string& path, vector<string>& reslist)
	{
		return YAMLoader::Instance()->list(path, reslist);
	}

	static bool list(const string& path, map<string, string>& resmap)
	{
		return YAMLoader::Instance()->list(path, resmap);
	}

	template<class DATA_TYPE> static DATA_TYPE config(const string& path)
	{
		static DATA_TYPE defval;
		DATA_TYPE value = defval;

		YAMLoader::Instance()->get(path, value);

		return value;
	}

	template<class DATA_TYPE> static bool config(const string& path, DATA_TYPE& value)
	{
		return YAMLoader::Instance()->get(path, value);
	}
}
//////////////////////////////////////////////////////////////////
#endif
